package config

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"os"
	"sync"
	"time"
)

const (
	DENV                 = "DENV"              // 环境变量：当前环境
	DCONFIG_MONGO_DSN    = "DCONFIG_MONGO_DSN" // 环境变量： 配置中心数据库连接
	DCONFIG_TABLE_PREFIX = "dsys_config_"      // 常量：配置集合名称前缀
)

var (
	denv              string   // 部署环境 dev=本地开发  tst=测试环境  uat=演示环境  prd=生产环境
	dconfig_mongo_dsn string   // 配置中心mongodb数据源连接uri
	cache             sync.Map // 所有配置项加载到缓存
)

func init() {
	denv = os.Getenv(DENV)
	dconfig_mongo_dsn = os.Getenv(DCONFIG_MONGO_DSN)
	if denv == "" || dconfig_mongo_dsn == "" {
		panic(errors.New("ERROR:hconfig-mongo init 未读取到环境变量 " + DENV + " 与 " + DCONFIG_MONGO_DSN))
	}
	fmt.Printf("hconfig-mongo init denv=%s  dconfig_mongo_dsn=%s \n", denv, dconfig_mongo_dsn)

	col := NewDatabase(dconfig_mongo_dsn).Collection(DCONFIG_TABLE_PREFIX + denv)
	loadConfig(col)
	go watchConfig(col)
}

type Config struct {
	Key    string                 `bson:"key"`    // 配置Key
	Value  map[string]interface{} `bson:"value"`  // 配置对象
	Remark string                 `bson:"remark"` // 备注说明
}

func loadConfig(col *mongo.Collection) {
	cur, err := col.Find(nil, bson.M{})
	if err != nil {
		panic(err)
	}
	var configs []*Config
	err = cur.All(nil, &configs)
	if err != nil {
		panic(err)
	}
	for _, conf := range configs {
		value, _ := json.Marshal(conf.Value)
		if value == nil {
			continue
		}
		cache.Store(conf.Key, value)
	}
}

func watchConfig(col *mongo.Collection) {
	ctx := context.TODO()
	cs, err := col.Watch(ctx, mongo.Pipeline{})
	if err != nil {
		fmt.Println(err.Error())
		time.Sleep(5 * time.Minute)
		watchConfig(col) // 异常情况，间隔5分钟重试
	}
	defer cs.Close(ctx)
	for cs.Next(ctx) {
		fmt.Println("Watch config ", cs.Current)
		loadConfig(col)
	}
}
